/*     */ package com.zimbra.cs.server;
/*     */ 
/*     */ import com.zimbra.common.localconfig.KnownKey;
/*     */ import com.zimbra.common.localconfig.LC;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.LogFactory;
/*     */ import com.zimbra.cs.account.Provisioning;
/*     */ import java.io.IOException;
/*     */ import java.io.OutputStream;
/*     */ import java.net.ServerSocket;
/*     */ import java.net.Socket;
/*     */ import java.net.SocketException;
/*     */ import java.util.HashSet;
/*     */ import java.util.LinkedList;
/*     */ import java.util.List;
/*     */ import java.util.Set;
/*     */ import java.util.concurrent.RejectedExecutionException;
/*     */ import java.util.concurrent.SynchronousQueue;
/*     */ import java.util.concurrent.ThreadPoolExecutor;
/*     */ import java.util.concurrent.TimeUnit;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public abstract class TcpServer
/*     */   implements Runnable, Server
/*     */ {
/*     */   private Log log;
/*     */   private ThreadPoolExecutor pooledExecutor;
/*     */   private ServerSocket serverSocket;
/*     */   private List<ProtocolHandler> activeHandlers;
/*     */   private boolean sslEnabled;
/*     */   private final ServerConfig config;
/*     */   private volatile boolean shutdownRequested;
/*     */   
/*     */   public TcpServer(ServerConfig config)
/*     */     throws ServiceException
/*     */   {
/*  53 */     this.config = config;
/*  54 */     this.sslEnabled = config.isSslEnabled();
/*  55 */     init(config.getMaxThreads(), config.getServerSocket());
/*     */   }
/*     */   
/*     */   public TcpServer(int maxThreads, ServerSocket serverSocket) {
/*  59 */     this.config = null;
/*  60 */     init(maxThreads, serverSocket);
/*     */   }
/*     */   
/*     */   private void init(int maxThreads, ServerSocket serverSocket) {
/*  64 */     this.serverSocket = serverSocket;
/*  65 */     this.log = LogFactory.getLog(TcpServer.class.getName() + "/" + serverSocket.getLocalPort());
/*     */     
/*  67 */     if (maxThreads <= 0) {
/*  68 */       this.log.warn("max handler threads " + maxThreads + " invalid; will use 10 threads instead");
/*  69 */       maxThreads = 10;
/*     */     }
/*     */     
/*     */ 
/*     */ 
/*  74 */     int keepAlive = this.config != null ? this.config.getThreadKeepAliveTime() : 120;
/*  75 */     this.pooledExecutor = new ThreadPoolExecutor(1, maxThreads, keepAlive, TimeUnit.SECONDS, new SynchronousQueue(), new TcpThreadFactory(getName(), false, 5));
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*  81 */     this.activeHandlers = new LinkedList();
/*     */   }
/*     */   
/*     */   public ServerConfig getConfig()
/*     */   {
/*  86 */     return this.config;
/*     */   }
/*     */   
/*     */   public int getConfigMaxIdleMilliSeconds() {
/*  90 */     if (this.config != null) {
/*  91 */       int secs = this.config.getMaxIdleTime();
/*  92 */       if (secs >= 0) {
/*  93 */         return secs * 1000;
/*     */       }
/*     */     }
/*  96 */     return -1;
/*     */   }
/*     */   
/*     */   protected void setSslEnabled(boolean ssl) {
/* 100 */     this.sslEnabled = ssl;
/*     */   }
/*     */   
/*     */   public boolean isSslEnabled() {
/* 104 */     return this.sslEnabled;
/*     */   }
/*     */   
/*     */   public void addActiveHandler(ProtocolHandler handler) {
/* 108 */     synchronized (this.activeHandlers) {
/* 109 */       this.activeHandlers.add(handler);
/*     */     }
/*     */   }
/*     */   
/*     */   public void removeActiveHandler(ProtocolHandler handler) {
/* 114 */     synchronized (this.activeHandlers) {
/* 115 */       this.activeHandlers.remove(handler);
/*     */     }
/*     */   }
/*     */   
/*     */   /* Error */
/*     */   protected int numActiveHandlers()
/*     */   {
/*     */     // Byte code:
/*     */     //   0: aload_0
/*     */     //   1: getfield 35	com/zimbra/cs/server/TcpServer:activeHandlers	Ljava/util/List;
/*     */     //   4: dup
/*     */     //   5: astore_1
/*     */     //   6: monitorenter
/*     */     //   7: aload_0
/*     */     //   8: getfield 35	com/zimbra/cs/server/TcpServer:activeHandlers	Ljava/util/List;
/*     */     //   11: invokeinterface 39 1 0
/*     */     //   16: aload_1
/*     */     //   17: monitorexit
/*     */     //   18: ireturn
/*     */     //   19: astore_2
/*     */     //   20: aload_1
/*     */     //   21: monitorexit
/*     */     //   22: aload_2
/*     */     //   23: athrow
/*     */     // Line number table:
/*     */     //   Java source line #120	-> byte code offset #0
/*     */     //   Java source line #121	-> byte code offset #7
/*     */     //   Java source line #122	-> byte code offset #19
/*     */     // Local variable table:
/*     */     //   start	length	slot	name	signature
/*     */     //   0	24	0	this	TcpServer
/*     */     //   5	16	1	Ljava/lang/Object;	Object
/*     */     //   19	4	2	localObject1	Object
/*     */     // Exception table:
/*     */     //   from	to	target	type
/*     */     //   7	18	19	finally
/*     */     //   19	22	19	finally
/*     */   }
/*     */   
/*     */   public int numThreads()
/*     */   {
/* 126 */     return this.pooledExecutor.getPoolSize();
/*     */   }
/*     */   
/*     */   private void shutdownActiveHandlers(boolean graceful) {
/* 130 */     synchronized (this.activeHandlers) {
/* 131 */       for (ProtocolHandler handler : this.activeHandlers) {
/* 132 */         if (graceful) {
/* 133 */           handler.gracefulShutdown("graceful shutdown requested");
/*     */         } else {
/* 135 */           handler.hardShutdown("hard shutdown requested");
/*     */         }
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   public void start()
/*     */   {
/* 143 */     Thread thread = new Thread(this);
/* 144 */     thread.setName(getName());
/* 145 */     thread.start();
/*     */   }
/*     */   
/*     */   public void stop()
/*     */   {
/* 150 */     stop(this.config.getShutdownTimeout());
/*     */   }
/*     */   
/*     */   public void stop(int forceShutdownAfterSeconds)
/*     */   {
/* 155 */     this.log.info(getName() + " initiating shutdown");
/* 156 */     this.shutdownRequested = true;
/*     */     try
/*     */     {
/* 159 */       this.serverSocket.close();
/* 160 */       Thread.yield();
/*     */     } catch (IOException ioe) {
/* 162 */       this.log.warn(getName() + " error closing server socket", ioe);
/*     */     }
/*     */     
/* 165 */     this.pooledExecutor.shutdown();
/*     */     
/* 167 */     shutdownActiveHandlers(true);
/*     */     
/* 169 */     if (numActiveHandlers() == 0) {
/* 170 */       this.log.info(getName() + " shutting down idle thread pool");
/* 171 */       this.pooledExecutor.shutdownNow();
/* 172 */       return;
/*     */     }
/*     */     
/* 175 */     this.log.info(getName() + " waiting " + forceShutdownAfterSeconds + " seconds for thread pool shutdown");
/*     */     try {
/* 177 */       this.pooledExecutor.awaitTermination(forceShutdownAfterSeconds, TimeUnit.SECONDS);
/*     */     } catch (InterruptedException ie) {
/* 179 */       this.log.warn(getName() + " interrupted while waiting for graceful shutdown", ie);
/*     */     }
/*     */     
/* 182 */     if (numActiveHandlers() == 0) {
/* 183 */       this.log.info(getName() + " thread pool terminated");
/* 184 */       return;
/*     */     }
/*     */     
/* 187 */     shutdownActiveHandlers(false);
/*     */     
/* 189 */     this.log.info(getName() + " shutdown complete");
/*     */   }
/*     */   
/*     */   public void run()
/*     */   {
/* 194 */     Thread.currentThread().setName(getName());
/*     */     
/* 196 */     this.log.info("Starting accept loop: %d core threads, %d max threads.", new Object[] { Integer.valueOf(this.pooledExecutor.getCorePoolSize()), Integer.valueOf(this.pooledExecutor.getMaximumPoolSize()) });
/*     */     for (;;)
/*     */     {
/* 199 */       if (!this.shutdownRequested) {
/*     */         try {
/* 201 */           Socket connection = this.serverSocket.accept();
/* 202 */           warnIfNecessary();
/* 203 */           ProtocolHandler handler = newProtocolHandler();
/* 204 */           handler.setConnection(connection);
/*     */           try {
/* 206 */             this.pooledExecutor.execute(handler);
/*     */           } catch (RejectedExecutionException e) {
/* 208 */             this.log.error("cannot handle connection; thread pool exhausted", e);
/*     */             
/*     */ 
/* 211 */             if ((this.config != null) && (!isSslEnabled())) {
/* 212 */               String message = this.config.getConnectionRejected();
/* 213 */               if (message != null) {
/*     */                 try {
/* 215 */                   OutputStream os = connection.getOutputStream();
/* 216 */                   if (os != null) {
/* 217 */                     os.write((message + "\r\n").getBytes());
/* 218 */                     os.flush();
/*     */                   }
/*     */                 }
/*     */                 catch (Throwable t) {}
/*     */               }
/*     */             }
/*     */             try
/*     */             {
/* 226 */               connection.close();
/*     */             }
/*     */             catch (Throwable t) {}
/*     */           }
/*     */         }
/*     */         catch (Throwable e) {
/* 232 */           if ((!(e instanceof SocketException)) || (!this.shutdownRequested))
/*     */           {
/*     */ 
/* 235 */             this.log.error("accept loop failed", e);
/*     */             try {
/* 237 */               Thread.sleep(1000L);
/*     */             } catch (InterruptedException ignore) {}
/*     */           }
/*     */         }
/*     */       }
/*     */     }
/* 243 */     this.log.info("finished accept loop");
/*     */   }
/*     */   
/*     */   private void warnIfNecessary() {
/* 247 */     if (this.log.isWarnEnabled()) {
/* 248 */       int warnPercent = LC.thread_pool_warn_percent.intValue();
/*     */       
/* 250 */       int active = this.pooledExecutor.getActiveCount() + 1;
/* 251 */       int max = this.pooledExecutor.getMaximumPoolSize();
/* 252 */       int utilization = active * 100 / max;
/* 253 */       if (utilization >= warnPercent) {
/* 254 */         this.log.warn("Thread pool is %d%% utilized.  %d out of %d threads in use.", new Object[] { Integer.valueOf(utilization), Integer.valueOf(active), Integer.valueOf(max) });
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   protected abstract ProtocolHandler newProtocolHandler();
/*     */   
/*     */   protected Set<String> getThrottleSafeHosts()
/*     */     throws ServiceException
/*     */   {
/* 264 */     Set<String> safeHosts = new HashSet();
/* 265 */     for (com.zimbra.cs.account.Server server : Provisioning.getInstance().getAllServers()) {
/* 266 */       safeHosts.add(server.getServiceHostname());
/*     */     }
/* 268 */     for (String ignoredHost : this.config.getThottleIgnoredHosts()) {
/* 269 */       safeHosts.add(ignoredHost);
/*     */     }
/* 271 */     return safeHosts;
/*     */   }
/*     */   
/*     */   protected Set<String> getThrottleWhitelist() throws ServiceException
/*     */   {
/* 276 */     Set<String> safeHosts = new HashSet();
/* 277 */     for (String whitelistHost : this.config.getThrottleWhitelist()) {
/* 278 */       safeHosts.add(whitelistHost);
/*     */     }
/* 280 */     return safeHosts;
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/server/TcpServer.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */